package com.xjk.ftp;

import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.ChannelSftp.LsEntry;
import com.jcraft.jsch.SftpException;
import com.xjk.data.Validator;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Vector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class SftpUtils{

    private static Logger logger = LoggerFactory.getLogger(SftpUtils.class);

    private static final String FILEPART = ".filepart";

    /**
     * 上传文件
     * 
     * @param directory
     *            上传的目录
     * @param uploadFile
     *            要上传的文件
     * @param sftp
     */
    public static void upload(String directory,String uploadFile, ChannelSftp sftp){
        createDir(directory, sftp);
        File file = new File(uploadFile);
        if (!file.exists()){
            return;
        }
        FileInputStream fs = null;
        try{
            sftp.cd(directory);
            fs = new FileInputStream(file);
            sftp.put(fs, file.getName());

        }catch (Exception e){
            e.printStackTrace();
        }finally{
            if (fs != null){
                try{
                    fs.close();
                }catch (IOException e){
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 上传文件
     * 
     * @param directory
     *            上传的目录
     * @param uploadFile
     *            要上传的文件
     * @param sftp
     */
    public static void uploadNew(String directory,String uploadFile,ChannelSftp sftp){
        createDir(directory, sftp);
        File file = new File(uploadFile);
        if (!file.exists()){
            return;
        }
        FileInputStream fs = null;
        try{
            sftp.cd(directory);
            fs = new FileInputStream(file);
            sftp.put(fs, file.getName() + FILEPART);
            renameFile(file.getName() + FILEPART, file.getName(), sftp);
        }catch (Exception e){
            e.printStackTrace();
        }finally{
            if (fs != null){
                try{
                    fs.close();
                }catch (IOException e){
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 移动文件(如果文件存在会自动覆盖，如果是当前路径下的文件输入文件名即可)
     * 
     * @param oldpath
     * @param newpath
     * @throws SftpException
     */
    public static void renameFile(String oldpath,String newpath,ChannelSftp sftp) throws SftpException {
        sftp.rename(oldpath, newpath);
    }

    /**
     * 下载文件
     * 
     * @param directory
     *            下载目录
     * @param downloadFile
     *            下载的文件
     * @param saveFile
     *            存在本地的路径
     * @param sftp
     */
    public static boolean download(String directory,String downloadFile,String saveFile,ChannelSftp sftp){
        InputStream is = null;
        try{
            sftp.cd(directory);
            is = sftp.get(directory + "/" + downloadFile);
            String newFilePath = saveFile.substring(0, saveFile.lastIndexOf("/"));
            String newFileName = saveFile.substring(saveFile.lastIndexOf("/") + 1, saveFile.length());
            FileUtil.copyFile(is, newFilePath, newFileName, null);
        }catch (Exception e){
            logger.error("8888 download file exception", e);
            return false;
        }finally{
            try{
                if(is != null){
                    is.close();
                }
            }catch (IOException e){
                
            }
        }
        return true;
    }

    /**
     * 删除文件
     * 
     * @param directory
     *            要删除文件所在目录
     * @param deleteFile
     *            要删除的文件
     * @param sftp
     */
    public static void delete(String directory,String deleteFile,ChannelSftp sftp){
        try{
            sftp.cd(directory);
            sftp.rm(deleteFile);
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 列出目录下的文件
     * 
     * @param directory
     *            要列出的目录
     * @param sftp
     * @return
     * @throws SftpException
     */
    @SuppressWarnings("unchecked")
    public static Vector<LsEntry> listFiles(String directory,ChannelSftp sftp) throws SftpException{
//        System.out.println(directory);
        return sftp.ls(directory);
    }

    /**
     * Description: 向FTP服务器上传文件
     * 
     * @param remotePath
     *            FTP服务器保存目录
     * @param localFileName
     *            上传到FTP服务器上的文件名
     * @return 成功返回true，否则返回false
     * @throws IOException
     */
    public static boolean sendFile(String remotePath,String localFileName,ChannelSftp sftp){
        // 得到文件名称
        if (localFileName == null || "".equals(localFileName)){
            return false;
        }
        // 如果路径是\\转化成/
        if (localFileName.indexOf("/") == -1){
            localFileName = localFileName.replace("\\\\", "\\");
            localFileName = localFileName.replace("\\", "/");
        }
        String toFileName = localFileName.substring(localFileName.lastIndexOf("/") == -1 ? 0 : localFileName.lastIndexOf("/") + 1, localFileName.length());
        FileInputStream fs = null;
        try{
            createDir(remotePath, sftp);
            File file = new File(localFileName);
            if (!file.exists()){
                return false;
            }
            fs = new FileInputStream(file);
            sftp.put(fs, toFileName);

        }catch (Exception e){
            e.printStackTrace();
            return false;
        }finally{
            if (fs != null){
                try{
                    fs.close();
                }catch (IOException e){
                    e.printStackTrace();
                }
            }
        }
        return true;
    }

    /**
     * Description: 向FTP服务器上传文件
     * 
     * @param remotePath
     *            FTP服务器保存目录
     * @param localFileName
     *            上传到FTP服务器上的文件名
     * @return 成功返回true，否则返回false
     * @throws IOException
     */
    public static boolean sendFileNew(String remotePath,String localFileName,ChannelSftp sftp){
        // 得到文件名称
        if (localFileName == null || "".equals(localFileName)){
            return false;
        }
        // 如果路径是\\转化成/
        if (localFileName.indexOf("/") == -1){
            localFileName = localFileName.replace("\\\\", "\\");
            localFileName = localFileName.replace("\\", "/");
        }
        logger.info("remote path :" + remotePath + ":localFileName:" + localFileName);
        String toFileName = localFileName.substring(localFileName.lastIndexOf("/") == -1 ? 0 : localFileName.lastIndexOf("/") + 1, localFileName.length());
        logger.info("remote path :" + remotePath + ":toFileName:" + toFileName);
        FileInputStream fs = null;
        try{
            createDir(remotePath, sftp);
            File file = new File(localFileName);
            if (!file.exists()){
                return false;
            }
            fs = new FileInputStream(file);
            sftp.put(fs, toFileName + FILEPART, ChannelSftp.RESUME);
            renameFile(toFileName + FILEPART, toFileName, sftp);
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }finally{
            if (fs != null){
                try{
                    fs.close();
                }catch (IOException e){
                    e.printStackTrace();
                }
            }
        }
        return true;
    }

    /**
     * Description: 向FTP服务器上传文件
     */
    public static boolean sendFile(String remotePath,File file,ChannelSftp sftp){
        // 得到文件名称
        if (file == null){
            return false;
        }
        String localFileName = file.getName();
        logger.info("remote path :" + remotePath + ":localFileName:" + localFileName);
        String toFileName = localFileName;
        logger.info("remote path :" + remotePath + ":toFileName:" + toFileName);
        FileInputStream fs = null;
        try{
            createDir(remotePath, sftp);
            if (!file.exists()){
                return false;
            }
            fs = new FileInputStream(file);
            sftp.put(fs, toFileName);

        }catch (Exception e){
            e.printStackTrace();
            return false;
        }finally{
            if (fs != null){
                try{
                    fs.close();
                }catch (IOException e){
                    e.printStackTrace();
                }
            }
        }
        return true;
    }

    /**
     * Description: 向FTP服务器上传文件
     */
    public static boolean sendFile(String remotePath,String fileName,InputStream is,ChannelSftp sftp){
        // 得到文件名称
        if (is == null){
            return false;
        }
        FileInputStream fs = null;
        try{
            createDir(remotePath, sftp);
            sftp.put(is, fileName);
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }finally{
            if (fs != null){
                try{
                    fs.close();
                }catch (IOException e){
                    e.printStackTrace();
                }
            }
        }
        return true;
    }

    /**
     * Description: 向FTP服务器上传文件
     */
    public static boolean sendFileNew(String remotePath,File file,ChannelSftp sftp){
        // 得到文件名称
        if (file == null){
            return false;
        }
        String localFileName = file.getName();
        //        logger.info("remote path :" + remotePath + ":localFileName:" + localFileName);
        String toFileName = localFileName;
        FileInputStream fs = null;
        try{
            createDir(remotePath, sftp);
            if (!file.exists()){
                return false;
            }
            fs = new FileInputStream(file);
            sftp.put(fs, toFileName + FILEPART);
            renameFile(toFileName + FILEPART, toFileName, sftp);
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }finally{
            if (fs != null){
                try{
                    fs.close();
                }catch (IOException e){
                    e.printStackTrace();
                }
            }
        }
        return true;
    }

    /**
     * 下载文件
     * 
     * @param serverName
     *            服务地址
     * @param port
     *            端口
     * @param userName
     *            用户名称
     * @param password
     *            密码
     * @param remotePath
     *            --服务器上目录
     * @param localPath
     *            --本地文件目录
     * @param isDel
     *            --是否删除原文件
     * @return 0：下载成功，1：下载失败 2： 文件正在上传
     */
    public static int readFile(String serverName,String port,String userName,String password,String remotePath,String localPath,String remoteBakPath,boolean isDel){
        int readIsSuccess = 0;
        if (remotePath == null || "".equals(remotePath)){
            readIsSuccess = 1;
            return readIsSuccess;
        }
        SftpConnectUtil sftpConnectUtil = new SftpConnectUtil();
        ChannelSftp sftp = sftpConnectUtil.connect(serverName, Integer.parseInt(port), userName, password, 180000);
        // 首先判断文件是否正在上传
        try{
            Vector<LsEntry> directorys = listFiles(remotePath, sftp);
            if (directorys.size() > 0){
                for (int k = 0; k < directorys.size(); k++){
                    LsEntry lsEntry = directorys.get(k);
                    if (null != lsEntry){
                        boolean isRead = true;
                        // 先判断文件名称的合法性 如果不合法就不继续下面的工作
                        isRead = judgeFilesName(lsEntry.getFilename());

                        // 如果条件匹配就进行文件的下载
                        if (isRead){
                            try{
                                String filename = lsEntry.getFilename();
                                if (".".equals(filename) || "..".equals(filename)){
                                    continue;
                                }
                                localPath = localPath.lastIndexOf("/") > -1 ? localPath : localPath + "/";
                                FileUtil.dynamicCreateDir(localPath);
                                boolean flag = download(remotePath, filename, localPath + "/" + filename, sftp);
                                if (!flag){
                                    readIsSuccess = 1;
                                }else{
                                    // 复制文件
                                    if (!Validator.isNullOrEmpty(remoteBakPath)){
                                        upload(remoteBakPath, localPath + "/" + filename, sftp);
                                    }
                                    // deleteFile
                                    if (isDel){
                                        delete(remotePath, filename, sftp);
                                    }
                                }
                            }catch (Exception e){
                                readIsSuccess = 3;
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }
        }catch (Exception e1){
            readIsSuccess = 2;
            e1.printStackTrace();
        }finally{
            sftpConnectUtil.closeChannel();
        }
        return readIsSuccess;
    }

    /**
     * create Directory 创建sftp上的目录
     * 增加了对根目录的判断
     * 
     * @param filepath
     * @param sftp
     */
    public static void createDir(String filepath,ChannelSftp sftp){
        if ("/".equals(filepath) || "".equals(filepath)){
            try{
                sftp.cd("/");
            }catch (Exception e){
                e.printStackTrace();
                logger.info("can not cd into :" + filepath);
            }
            return;
        }
        boolean bcreated = false;
        boolean bparent = false;
        File file = new File(filepath);
        String ppath = null;
        if (file.getParent() != null){
            ppath = file.getParent().replace("\\", "//");
        }else{
            ppath = filepath;
        }
        try{
            sftp.cd(ppath);
            bparent = true;
        }catch (SftpException e1){
            bparent = false;
        }
        try{
            if (bparent){
                try{
                    sftp.cd(filepath);
                    bcreated = true;
                }catch (Exception e){
                    bcreated = false;
                }
                if (!bcreated){
                    sftp.mkdir(filepath);
                    sftp.cd(filepath);
                    bcreated = true;
                }
                return;
            }else{
                createDir(ppath, sftp);
                sftp.cd(ppath);
                sftp.mkdir(filepath);
            }
        }catch (SftpException e){
            logger.info("mkdir failed :" + filepath);
            e.printStackTrace();
        }

        try{
            sftp.cd(filepath);
        }catch (SftpException e){
            e.printStackTrace();
            logger.info("can not cd into :" + filepath);
        }

    }

    /**
     * 判断文件名称是否符合匹配字符
     * 
     * @param fileName
     *            文件名称
     * @return
     */
    private static boolean judgeFilesName(String fileName){
        boolean flag = true;
        if (null == fileName || "".equals(fileName)){
            flag = false;
            return flag;
        }

        String[] name = fileName.split("\\.");
        if (name.length == 0){
            flag = false;
            return flag;
        }
        for (int i = 0; i < name.length; i++){
            if (null == name[i] || name[i].equals("")){
                flag = false;
                return flag;
            }
        }

        return flag;
    }

    public static int moveFile(ChannelSftp sftp,String filename,String from,String to){
        try{
            sftp.cd(to);
        }catch (SftpException e){
            e.printStackTrace();
            // 目录不存在，则创建新目录
            createDir(to, sftp);
        }
        try{
            sftp.cd(to);
            from = from.endsWith("/") ? from : from + "/";
            to = to.endsWith("/") ? to : to + "/";
            sftp.rename(from + filename, to + filename);
            return 1;
        }catch (Exception e){
            e.printStackTrace();
            return 0;
        }
    }
}
